home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / Kasumi / source / blt_reference_yuv.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-11-30  |  41.8 KB  |  1,542 lines

  1. #include <vd2/system/vdtypes.h>
  2. #include <vd2/system/vdstl.h>
  3. #include <vd2/system/cpuaccel.h>
  4. #include <vd2/system/memory.h>
  5. #include <vd2/Kasumi/pixmap.h>
  6. #include <vd2/Kasumi/pixmaputils.h>
  7.  
  8. #include "blt_spanutils.h"
  9.  
  10. using namespace nsVDPixmapSpanUtils;
  11.  
  12. namespace {
  13.     struct YCbCrToRGB {
  14.         sint16 y_tab[256];
  15.         sint16 r_cr_tab[256];
  16.         sint16 b_cb_tab[256];
  17.         sint16 g_cr_tab[256];
  18.         sint16 g_cb_tab[256];
  19.         uint8 cliptab[277+256+279];
  20.         uint16 cliptab15[277+256+279];
  21.         uint16 cliptab16[277+256+279];
  22.  
  23.         YCbCrToRGB() {
  24.             int i;
  25.  
  26.             memset(cliptab, 0, 277);
  27.             memset(cliptab+277+256, 255, 279);
  28.  
  29.             memset(cliptab15, 0, sizeof cliptab15[0] * 277);
  30.             memset(cliptab16, 0, sizeof cliptab16[0] * 277);
  31.             memset(cliptab15+277+256, 0xff, sizeof cliptab15[0] * 279);
  32.             memset(cliptab16+277+256, 0xff, sizeof cliptab16[0] * 279);
  33.  
  34.             for(i=0; i<256; ++i) {
  35.                 y_tab[i] = (sint16)(((i-16) * 76309 + 32768) >> 16);
  36.                 r_cr_tab[i] = (sint16)(((i-128) * 104597 + 32768) >> 16);
  37.                 b_cb_tab[i] = (sint16)(((i-128) * 132201 + 32768) >> 16);
  38.                 g_cr_tab[i] = (sint16)(((i-128) * -53279 + 32768) >> 16);
  39.                 g_cb_tab[i] = (sint16)(((i-128) * -25674 + 32768) >> 16);
  40.                 cliptab[i+277] = (uint8)i;
  41.                 cliptab15[i+277] = 0x421 * ((unsigned)i>>3);
  42.                 cliptab16[i+277] = 0x801 * ((unsigned)i>>3) + 0x20 * ((unsigned)i>>2);
  43.             }
  44.         }
  45.     } colorconv;
  46.  
  47.     struct YCbCrFormatInfo {
  48.         ptrdiff_t    ystep;
  49.         ptrdiff_t    cstep;
  50.         ptrdiff_t    yinc[4];
  51.         ptrdiff_t    cinc[4];
  52.         sint8        ypos[4];
  53.         sint8        cbpos[4];
  54.         sint8        crpos[4];
  55.     };
  56.  
  57.     YCbCrFormatInfo        g_formatInfo_YUV444_Planar    = { -4, -4, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3}};
  58.     YCbCrFormatInfo        g_formatInfo_YUV422_YUYV    = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,2,4,6}, {1,1,5,5}, {3,3,7,7}};
  59.     YCbCrFormatInfo        g_formatInfo_YUV422_UYVY    = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {1,3,5,7}, {0,0,4,4}, {2,2,6,6}};
  60.     YCbCrFormatInfo        g_formatInfo_YUV420_YV12    = { -4, -2, {-1,-1,-1,-1}, { 0,-1, 0,-1}, {0,1,2,3}, {0,0,1,1}, {0,0,1,1}};
  61.     YCbCrFormatInfo        g_formatInfo_YUV411_YV12    = { -4, -1, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,0,0,0}, {0,0,0,0}};
  62.  
  63.     inline uint16 ycbcr_to_1555(uint8 y, uint8 cb0, uint8 cr0) {
  64.         const uint16 *p = &colorconv.cliptab15[277 + colorconv.y_tab[y]];
  65.         uint32 r = 0x7c00 & p[colorconv.r_cr_tab[cr0]];
  66.         uint32 g = 0x03e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  67.         uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]];
  68.  
  69.         return r + g + b;
  70.     }
  71.  
  72.     inline uint16 ycbcr_to_565(uint8 y, uint8 cb0, uint8 cr0) {
  73.         const uint16 *p = &colorconv.cliptab16[277 + colorconv.y_tab[y]];
  74.         uint32 r = 0xf800 & p[colorconv.r_cr_tab[cr0]];
  75.         uint32 g = 0x07e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  76.         uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]];
  77.  
  78.         return r + g + b;
  79.     }
  80.  
  81.     inline void ycbcr_to_888(uint8 *dst, uint8 y, uint8 cb0, uint8 cr0) {
  82.         const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]];
  83.         uint8 r = p[colorconv.r_cr_tab[cr0]];
  84.         uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  85.         uint8 b = p[colorconv.b_cb_tab[cb0]];
  86.  
  87.         dst[0] = b;
  88.         dst[1] = g;
  89.         dst[2] = r;
  90.     }
  91.  
  92.     inline uint32 ycbcr_to_8888(uint8 y, uint8 cb0, uint8 cr0) {
  93.         const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]];
  94.         uint8 r = p[colorconv.r_cr_tab[cr0]];
  95.         uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  96.         uint8 b = p[colorconv.b_cb_tab[cb0]];
  97.  
  98.         return (r << 16) + (g << 8) + b;
  99.     }
  100.  
  101.     void VDYCbCrToXRGB1555Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  102.         uint16 *dst = (uint16 *)dst0;
  103.  
  104.         do {
  105.             *dst++ = ycbcr_to_1555(*y++, *cb++, *cr++);
  106.         } while(--w);
  107.     }
  108.  
  109.     void VDYCbCrToRGB565Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  110.         uint16 *dst = (uint16 *)dst0;
  111.  
  112.         do {
  113.             *dst++ = ycbcr_to_565(*y++, *cb++, *cr++);
  114.         } while(--w);
  115.     }
  116.  
  117.     void VDYCbCrToRGB888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  118.         uint8 *dst = (uint8 *)dst0;
  119.  
  120.         do {
  121.             ycbcr_to_888(dst, *y++, *cb++, *cr++);
  122.             dst += 3;
  123.         } while(--w);
  124.     }
  125.  
  126.     void VDYCbCrToXRGB8888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  127.         uint32 *dst = (uint32 *)dst0;
  128.  
  129.         do {
  130.             *dst++ = ycbcr_to_8888(*y++, *cb++, *cr++);
  131.         } while(--w);
  132.     }
  133.  
  134.     void VDYCbCrToUYVYSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  135.         uint32 *dst = (uint32 *)dst0;
  136.  
  137.         if (--w) {
  138.             do {
  139.                 *dst++ = (uint32)*cb++ + ((uint32)y[0] << 8) + ((uint32)*cr++ << 16) + ((uint32)y[1] << 24);
  140.                 y += 2;
  141.             } while((sint32)(w-=2)>0);
  142.         }
  143.  
  144.         if (!(w & 1))
  145.             *dst++ = (uint32)*cb + ((uint32)y[0] << 8) + ((uint32)*cr << 16) + ((uint32)y[0] << 24);
  146.     }
  147.  
  148.     void VDYCbCrToYUYVSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  149.         uint32 *dst = (uint32 *)dst0;
  150.  
  151.         if (--w) {
  152.             do {
  153.                 *dst++ = (uint32)y[0] + ((uint32)*cb++ << 8) + ((uint32)y[1] << 16) + ((uint32)*cr++ << 24);
  154.                 y += 2;
  155.             } while((sint32)(w-=2)>0);
  156.         }
  157.  
  158.         if (!(w & 1))
  159.             *dst++ = (uint32)y[0] + ((uint32)*cb << 8) + ((uint32)y[0] << 16) + ((uint32)*cr << 24);
  160.     }
  161.  
  162.     void VDYCbCrToRGB1555Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  163.         const ptrdiff_t ystep    = formatinfo.ystep;
  164.         const ptrdiff_t cstep    = formatinfo.cstep;
  165.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  166.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  167.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  168.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  169.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  170.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  171.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  172.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  173.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  174.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  175.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  176.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  177.  
  178.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  179.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  180.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  181.         dst        = (char *)dst + 2*((w-1) & ~3);
  182.  
  183.         int y = 0;
  184.         do {
  185.             const uint8 *ysrc    = (const uint8 *)yrow;
  186.             const uint8 *crsrc    = (const uint8 *)crrow;
  187.             const uint8 *cbsrc    = (const uint8 *)cbrow;
  188.             uint16 *out = (uint16 *)dst;
  189.             int w2 = -w;
  190.  
  191.             switch(w2 & 3) {
  192.                 do {
  193.             case 0:    out[3] = ycbcr_to_1555(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  194.             case 1:    out[2] = ycbcr_to_1555(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  195.             case 2:    out[1] = ycbcr_to_1555(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  196.             case 3:    out[0] = ycbcr_to_1555(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  197.                     out -= 4;
  198.                     ysrc += ystep;
  199.                     crsrc += cstep;
  200.                     cbsrc += cstep;
  201.                 } while((w2 += 4) < 0);
  202.             }
  203.  
  204.             dst        = (char *)dst + dststride;
  205.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  206.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  207.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  208.         } while(++y < h);
  209.     }
  210.  
  211.     void VDYCbCrToRGB565Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  212.         const ptrdiff_t ystep    = formatinfo.ystep;
  213.         const ptrdiff_t cstep    = formatinfo.cstep;
  214.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  215.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  216.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  217.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  218.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  219.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  220.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  221.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  222.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  223.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  224.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  225.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  226.  
  227.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  228.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  229.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  230.         dst        = (char *)dst + 2*((w-1) & ~3);
  231.  
  232.         int y = 0;
  233.         do {
  234.             const uint8 *ysrc = (const uint8 *)yrow;
  235.             const uint8 *crsrc = (const uint8 *)crrow;
  236.             const uint8 *cbsrc = (const uint8 *)cbrow;
  237.             uint16 *out = (uint16 *)dst;
  238.             int w2 = -w;
  239.  
  240.             switch(w2 & 3) {
  241.                 do {
  242.             case 0:    out[3] = ycbcr_to_565(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  243.             case 1:    out[2] = ycbcr_to_565(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  244.             case 2:    out[1] = ycbcr_to_565(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  245.             case 3:    out[0] = ycbcr_to_565(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  246.                     out -= 4;
  247.                     ysrc += ystep;
  248.                     crsrc += cstep;
  249.                     cbsrc += cstep;
  250.                 } while((w2 += 4) < 0);
  251.             }
  252.  
  253.             dst        = (char *)dst + dststride;
  254.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  255.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  256.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  257.         } while(++y < h);
  258.     }
  259.  
  260.     void VDYCbCrToRGB888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  261.         const ptrdiff_t ystep    = formatinfo.ystep;
  262.         const ptrdiff_t cstep    = formatinfo.cstep;
  263.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  264.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  265.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  266.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  267.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  268.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  269.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  270.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  271.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  272.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  273.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  274.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  275.  
  276.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  277.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  278.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  279.         dst        = (char *)dst + 3*((w-1) & ~3);
  280.  
  281.         int y = 0;
  282.         do {
  283.             const uint8 *ysrc    = (const uint8 *)yrow;
  284.             const uint8 *crsrc    = (const uint8 *)crrow;
  285.             const uint8 *cbsrc    = (const uint8 *)cbrow;
  286.             uint8 *out = (uint8 *)dst;
  287.             int w2 = -w;
  288.  
  289.             switch(w2 & 3) {
  290.                 do {
  291.             case 0:    ycbcr_to_888(out+9, ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  292.             case 1:    ycbcr_to_888(out+6, ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  293.             case 2:    ycbcr_to_888(out+3, ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  294.             case 3:    ycbcr_to_888(out, ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  295.                     out -= 12;
  296.                     ysrc += ystep;
  297.                     crsrc += cstep;
  298.                     cbsrc += cstep;
  299.                 } while((w2 += 4) < 0);
  300.             }
  301.  
  302.             dst        = (char *)dst + dststride;
  303.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  304.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  305.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  306.         } while(++y < h);
  307.     }
  308.  
  309.     void VDYCbCrToRGB8888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  310.         const ptrdiff_t ystep    = formatinfo.ystep;
  311.         const ptrdiff_t cstep    = formatinfo.cstep;
  312.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  313.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  314.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  315.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  316.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  317.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  318.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  319.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  320.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  321.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  322.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  323.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  324.  
  325.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  326.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  327.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  328.         dst        = (char *)dst + 4*((w-1) & ~3);
  329.  
  330.         int y = 0;
  331.         do {
  332.             const uint8 *ysrc    = (const uint8 *)yrow;
  333.             const uint8 *crsrc    = (const uint8 *)crrow;
  334.             const uint8 *cbsrc    = (const uint8 *)cbrow;
  335.             uint32 *out = (uint32 *)dst;
  336.             int w2 = -w;
  337.  
  338.             switch(w2 & 3) {
  339.                 do {
  340.             case 0:    out[3] = ycbcr_to_8888(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  341.             case 1:    out[2] = ycbcr_to_8888(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  342.             case 2:    out[1] = ycbcr_to_8888(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  343.             case 3:    out[0] = ycbcr_to_8888(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  344.                     out -= 4;
  345.                     ysrc += ystep;
  346.                     crsrc += cstep;
  347.                     cbsrc += cstep;
  348.                 } while((w2 += 4) < 0);
  349.             }
  350.  
  351.             dst        = (char *)dst + dststride;
  352.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  353.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  354.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  355.         } while(++y < h);
  356.     }
  357. }
  358.  
  359. #define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h)
  360.  
  361. DECLARE_YUV(UYVY, XRGB1555) {
  362.     do {
  363.         const uint8 *src = (const uint8 *)src0;
  364.         uint16 *dst = (uint16 *)dst0;
  365.  
  366.         // convert first pixel
  367.         int cb, cr;
  368.         int rc0, gc0, bc0, rc1, gc1, bc1;
  369.         const uint16 *y;
  370.  
  371.         cb = src[0];
  372.         cr = src[2];
  373.         rc1 = colorconv.r_cr_tab[cr];
  374.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  375.         bc1 = colorconv.b_cb_tab[cb];
  376.  
  377.         y = &colorconv.cliptab15[277 + colorconv.y_tab[src[1]]];
  378.         *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  379.  
  380.         // convert pairs of pixels
  381.         int w2 = w;
  382.  
  383.         if ((w2 -= 2) > 0) {
  384.             do {
  385.                 rc0 = rc1;
  386.                 gc0 = gc1;
  387.                 bc0 = bc1;
  388.  
  389.                 cb = src[4];
  390.                 cr = src[6];
  391.                 rc1 = colorconv.r_cr_tab[cr];
  392.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  393.                 bc1 = colorconv.b_cb_tab[cb];
  394.  
  395.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]];
  396.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  397.  
  398.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[5]]];
  399.                 dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  400.  
  401.                 dst += 2;
  402.                 src += 4;
  403.             } while((w2 -= 2) > 0);
  404.         }
  405.  
  406.         // handle oddballs
  407.         if (!(w2 & 1)) {
  408.             y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]];
  409.             *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  410.         }
  411.  
  412.         vdptrstep(src0, srcpitch);
  413.         vdptrstep(dst0, dstpitch);
  414.     } while(--h);
  415. }
  416.  
  417. DECLARE_YUV(UYVY, RGB565) {
  418.     do {
  419.         const uint8 *src = (const uint8 *)src0;
  420.         uint16 *dst = (uint16 *)dst0;
  421.  
  422.         // convert first pixel
  423.         int cb, cr;
  424.         int rc0, gc0, bc0, rc1, gc1, bc1;
  425.         const uint16 *y;
  426.  
  427.         cb = src[0];
  428.         cr = src[2];
  429.         rc1 = colorconv.r_cr_tab[cr];
  430.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  431.         bc1 = colorconv.b_cb_tab[cb];
  432.  
  433.         y = &colorconv.cliptab16[277 + colorconv.y_tab[src[1]]];
  434.         *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  435.  
  436.         // convert pairs of pixels
  437.         int w2 = w;
  438.  
  439.         if ((w2 -= 2) > 0) {
  440.             do {
  441.                 rc0 = rc1;
  442.                 gc0 = gc1;
  443.                 bc0 = bc1;
  444.  
  445.                 cb = src[4];
  446.                 cr = src[6];
  447.                 rc1 = colorconv.r_cr_tab[cr];
  448.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  449.                 bc1 = colorconv.b_cb_tab[cb];
  450.  
  451.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]];
  452.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  453.  
  454.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[5]]];
  455.                 dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  456.  
  457.                 dst += 2;
  458.                 src += 4;
  459.             } while((w2 -= 2) > 0);
  460.         }
  461.  
  462.         // handle oddballs
  463.         if (!(w2 & 1)) {
  464.             y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]];
  465.             *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  466.         }
  467.  
  468.         vdptrstep(src0, srcpitch);
  469.         vdptrstep(dst0, dstpitch);
  470.     } while(--h);
  471. }
  472.  
  473. DECLARE_YUV(UYVY, RGB888) {
  474.     do {
  475.         const uint8 *src = (const uint8 *)src0;
  476.         uint8 *dst = (uint8 *)dst0;
  477.  
  478.         // convert first pixel
  479.         int cb, cr;
  480.         int rc0, gc0, bc0, rc1, gc1, bc1;
  481.         const uint8 *y;
  482.  
  483.         cb = src[0];
  484.         cr = src[2];
  485.         rc1 = colorconv.r_cr_tab[cr];
  486.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  487.         bc1 = colorconv.b_cb_tab[cb];
  488.  
  489.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]];
  490.         dst[0] = y[bc1];
  491.         dst[1] = y[gc1];
  492.         dst[2] = y[rc1];
  493.         dst += 3;
  494.  
  495.         // convert pairs of pixels
  496.         int w2 = w;
  497.  
  498.         if ((w2 -= 2) > 0) {
  499.             do {
  500.                 rc0 = rc1;
  501.                 gc0 = gc1;
  502.                 bc0 = bc1;
  503.  
  504.                 cb = src[4];
  505.                 cr = src[6];
  506.                 rc1 = colorconv.r_cr_tab[cr];
  507.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  508.                 bc1 = colorconv.b_cb_tab[cb];
  509.  
  510.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  511.                 dst[0] = y[(bc0+bc1+1)>>1];
  512.                 dst[1] = y[(gc0+gc1+1)>>1];
  513.                 dst[2] = y[(rc0+rc1+1)>>1];
  514.  
  515.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]];
  516.                 dst[3] = y[bc1];
  517.                 dst[4] = y[gc1];
  518.                 dst[5] = y[rc1];
  519.  
  520.                 dst += 6;
  521.                 src += 4;
  522.             } while((w2 -= 2) > 0);
  523.         }
  524.  
  525.         // handle oddballs
  526.         if (!(w2 & 1)) {
  527.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  528.             dst[0] = y[bc1];
  529.             dst[1] = y[gc1];
  530.             dst[2] = y[rc1];
  531.         }
  532.  
  533.         vdptrstep(src0, srcpitch);
  534.         vdptrstep(dst0, dstpitch);
  535.     } while(--h);
  536. }
  537.  
  538. DECLARE_YUV(UYVY, XRGB8888) {
  539.     do {
  540.         const uint8 *src = (const uint8 *)src0;
  541.         uint8 *dst = (uint8 *)dst0;
  542.  
  543.         // convert first pixel
  544.         int cb, cr;
  545.         int rc0, gc0, bc0, rc1, gc1, bc1;
  546.         const uint8 *y;
  547.  
  548.         cb = src[0];
  549.         cr = src[2];
  550.         rc1 = colorconv.r_cr_tab[cr];
  551.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  552.         bc1 = colorconv.b_cb_tab[cb];
  553.  
  554.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]];
  555.         dst[0] = y[bc1];
  556.         dst[1] = y[gc1];
  557.         dst[2] = y[rc1];
  558.         dst += 4;
  559.  
  560.         // convert pairs of pixels
  561.         int w2 = w;
  562.  
  563.         if ((w2 -= 2) > 0) {
  564.             do {
  565.                 rc0 = rc1;
  566.                 gc0 = gc1;
  567.                 bc0 = bc1;
  568.  
  569.                 cb = src[4];
  570.                 cr = src[6];
  571.                 rc1 = colorconv.r_cr_tab[cr];
  572.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  573.                 bc1 = colorconv.b_cb_tab[cb];
  574.  
  575.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  576.                 dst[0] = y[(bc0+bc1+1)>>1];
  577.                 dst[1] = y[(gc0+gc1+1)>>1];
  578.                 dst[2] = y[(rc0+rc1+1)>>1];
  579.  
  580.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]];
  581.                 dst[4] = y[bc1];
  582.                 dst[5] = y[gc1];
  583.                 dst[6] = y[rc1];
  584.  
  585.                 dst += 8;
  586.                 src += 4;
  587.             } while((w2 -= 2) > 0);
  588.         }
  589.  
  590.         // handle oddballs
  591.         if (!(w2 & 1)) {
  592.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  593.             dst[0] = y[bc1];
  594.             dst[1] = y[gc1];
  595.             dst[2] = y[rc1];
  596.         }
  597.  
  598.         vdptrstep(src0, srcpitch);
  599.         vdptrstep(dst0, dstpitch);
  600.     } while(--h);
  601. }
  602.  
  603. DECLARE_YUV(YUYV, XRGB1555) {
  604.     do {
  605.         const uint8 *src = (const uint8 *)src0;
  606.         uint16 *dst = (uint16 *)dst0;
  607.  
  608.         // convert first pixel
  609.         int cb, cr;
  610.         int rc0, gc0, bc0, rc1, gc1, bc1;
  611.         const uint16 *y;
  612.  
  613.         cb = src[1];
  614.         cr = src[3];
  615.         rc1 = colorconv.r_cr_tab[cr];
  616.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  617.         bc1 = colorconv.b_cb_tab[cb];
  618.  
  619.         y = &colorconv.cliptab15[277 + colorconv.y_tab[src[0]]];
  620.         *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  621.  
  622.         // convert pairs of pixels
  623.         int w2 = w;
  624.  
  625.         if ((w2 -= 2) > 0) {
  626.             do {
  627.                 rc0 = rc1;
  628.                 gc0 = gc1;
  629.                 bc0 = bc1;
  630.  
  631.                 cb = src[5];
  632.                 cr = src[7];
  633.                 rc1 = colorconv.r_cr_tab[cr];
  634.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  635.                 bc1 = colorconv.b_cb_tab[cb];
  636.  
  637.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]];
  638.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  639.  
  640.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[4]]];
  641.                 dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  642.  
  643.                 dst += 2;
  644.                 src += 4;
  645.             } while((w2 -= 2) > 0);
  646.         }
  647.  
  648.         // handle oddballs
  649.         if (!(w2 & 1)) {
  650.             y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]];
  651.             *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  652.         }
  653.  
  654.         vdptrstep(src0, srcpitch);
  655.         vdptrstep(dst0, dstpitch);
  656.     } while(--h);
  657. }
  658.  
  659. DECLARE_YUV(YUYV, RGB565) {
  660.     do {
  661.         const uint8 *src = (const uint8 *)src0;
  662.         uint16 *dst = (uint16 *)dst0;
  663.  
  664.         // convert first pixel
  665.         int cb, cr;
  666.         int rc0, gc0, bc0, rc1, gc1, bc1;
  667.         const uint16 *y;
  668.  
  669.         cb = src[1];
  670.         cr = src[3];
  671.         rc1 = colorconv.r_cr_tab[cr];
  672.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  673.         bc1 = colorconv.b_cb_tab[cb];
  674.  
  675.         y = &colorconv.cliptab16[277 + colorconv.y_tab[src[0]]];
  676.         *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  677.  
  678.         // convert pairs of pixels
  679.         int w2 = w;
  680.  
  681.         if ((w2 -= 2) > 0) {
  682.             do {
  683.                 rc0 = rc1;
  684.                 gc0 = gc1;
  685.                 bc0 = bc1;
  686.  
  687.                 cb = src[5];
  688.                 cr = src[7];
  689.                 rc1 = colorconv.r_cr_tab[cr];
  690.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  691.                 bc1 = colorconv.b_cb_tab[cb];
  692.  
  693.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]];
  694.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  695.  
  696.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[4]]];
  697.                 dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  698.  
  699.                 dst += 2;
  700.                 src += 4;
  701.             } while((w2 -= 2) > 0);
  702.         }
  703.  
  704.         // handle oddballs
  705.         if (!(w2 & 1)) {
  706.             y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]];
  707.             *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  708.         }
  709.  
  710.         vdptrstep(src0, srcpitch);
  711.         vdptrstep(dst0, dstpitch);
  712.     } while(--h);
  713. }
  714.  
  715. DECLARE_YUV(YUYV, RGB888) {
  716.     do {
  717.         const uint8 *src = (const uint8 *)src0;
  718.         uint8 *dst = (uint8 *)dst0;
  719.  
  720.         // convert first pixel
  721.         int cb, cr;
  722.         int rc0, gc0, bc0, rc1, gc1, bc1;
  723.         const uint8 *y;
  724.  
  725.         cb = src[1];
  726.         cr = src[3];
  727.         rc1 = colorconv.r_cr_tab[cr];
  728.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  729.         bc1 = colorconv.b_cb_tab[cb];
  730.  
  731.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]];
  732.         dst[0] = y[bc1];
  733.         dst[1] = y[gc1];
  734.         dst[2] = y[rc1];
  735.         dst += 3;
  736.  
  737.         // convert pairs of pixels
  738.         int w2 = w;
  739.  
  740.         if ((w2 -= 2) > 0) {
  741.             do {
  742.                 rc0 = rc1;
  743.                 gc0 = gc1;
  744.                 bc0 = bc1;
  745.  
  746.                 cb = src[5];
  747.                 cr = src[7];
  748.                 rc1 = colorconv.r_cr_tab[cr];
  749.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  750.                 bc1 = colorconv.b_cb_tab[cb];
  751.  
  752.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  753.                 dst[0] = y[(bc0+bc1+1)>>1];
  754.                 dst[1] = y[(gc0+gc1+1)>>1];
  755.                 dst[2] = y[(rc0+rc1+1)>>1];
  756.  
  757.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]];
  758.                 dst[3] = y[bc1];
  759.                 dst[4] = y[gc1];
  760.                 dst[5] = y[rc1];
  761.  
  762.                 dst += 6;
  763.                 src += 4;
  764.             } while((w2 -= 2) > 0);
  765.         }
  766.  
  767.         // handle oddballs
  768.         if (!(w2 & 1)) {
  769.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  770.             dst[0] = y[bc1];
  771.             dst[1] = y[gc1];
  772.             dst[2] = y[rc1];
  773.         }
  774.  
  775.         vdptrstep(src0, srcpitch);
  776.         vdptrstep(dst0, dstpitch);
  777.     } while(--h);
  778. }
  779.  
  780. DECLARE_YUV(YUYV, XRGB8888) {
  781.     do {
  782.         const uint8 *src = (const uint8 *)src0;
  783.         uint8 *dst = (uint8 *)dst0;
  784.  
  785.         // convert first pixel
  786.         int cb, cr;
  787.         int rc0, gc0, bc0, rc1, gc1, bc1;
  788.         const uint8 *y;
  789.  
  790.         cb = src[1];
  791.         cr = src[3];
  792.         rc1 = colorconv.r_cr_tab[cr];
  793.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  794.         bc1 = colorconv.b_cb_tab[cb];
  795.  
  796.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]];
  797.         dst[0] = y[bc1];
  798.         dst[1] = y[gc1];
  799.         dst[2] = y[rc1];
  800.         dst += 4;
  801.  
  802.         // convert pairs of pixels
  803.         int w2 = w;
  804.  
  805.         if ((w2 -= 2) > 0) {
  806.             do {
  807.                 rc0 = rc1;
  808.                 gc0 = gc1;
  809.                 bc0 = bc1;
  810.  
  811.                 cb = src[5];
  812.                 cr = src[7];
  813.                 rc1 = colorconv.r_cr_tab[cr];
  814.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  815.                 bc1 = colorconv.b_cb_tab[cb];
  816.  
  817.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  818.                 dst[0] = y[(bc0+bc1+1)>>1];
  819.                 dst[1] = y[(gc0+gc1+1)>>1];
  820.                 dst[2] = y[(rc0+rc1+1)>>1];
  821.  
  822.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]];
  823.                 dst[4] = y[bc1];
  824.                 dst[5] = y[gc1];
  825.                 dst[6] = y[rc1];
  826.  
  827.                 dst += 8;
  828.                 src += 4;
  829.             } while((w2 -= 2) > 0);
  830.         }
  831.  
  832.         // handle oddballs
  833.         if (!(w2 & 1)) {
  834.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  835.             dst[0] = y[bc1];
  836.             dst[1] = y[gc1];
  837.             dst[2] = y[rc1];
  838.         }
  839.  
  840.         vdptrstep(src0, srcpitch);
  841.         vdptrstep(dst0, dstpitch);
  842.     } while(--h);
  843. }
  844.  
  845. DECLARE_YUV(Y8, XRGB1555) {
  846.     uint16 *dst = (uint16 *)dst0;
  847.     const uint8 *src = (const uint8 *)src0;
  848.  
  849.     dstpitch -= 2*w;
  850.     srcpitch -= w;
  851.  
  852.     do {
  853.         vdpixsize w2 = w;
  854.  
  855.         do {
  856.             *dst++ = colorconv.cliptab15[colorconv.y_tab[*src++] + 277];
  857.         } while(--w2);
  858.  
  859.         vdptrstep(src, srcpitch);
  860.         vdptrstep(dst, dstpitch);
  861.     } while(--h);
  862. }
  863.  
  864. DECLARE_YUV(Y8, RGB565) {
  865.     uint16 *dst = (uint16 *)dst0;
  866.     const uint8 *src = (const uint8 *)src0;
  867.  
  868.     dstpitch -= 2*w;
  869.     srcpitch -= w;
  870.  
  871.     do {
  872.         vdpixsize w2 = w;
  873.  
  874.         do {
  875.             *dst++ = colorconv.cliptab16[colorconv.y_tab[*src++] + 277];
  876.         } while(--w2);
  877.  
  878.         vdptrstep(src, srcpitch);
  879.         vdptrstep(dst, dstpitch);
  880.     } while(--h);
  881. }
  882.  
  883. DECLARE_YUV(Y8, RGB888) {
  884.     uint8 *dst = (uint8 *)dst0;
  885.     const uint8 *src = (const uint8 *)src0;
  886.  
  887.     dstpitch -= 3*w;
  888.     srcpitch -= w;
  889.  
  890.     do {
  891.         vdpixsize w2 = w;
  892.  
  893.         do {
  894.             dst[0] = dst[1] = dst[2] = colorconv.cliptab[colorconv.y_tab[*src++] + 277];
  895.             dst += 3;
  896.         } while(--w2);
  897.  
  898.         vdptrstep(src, srcpitch);
  899.         vdptrstep(dst, dstpitch);
  900.     } while(--h);
  901. }
  902.  
  903. DECLARE_YUV(Y8, XRGB8888) {
  904.     uint32 *dst = (uint32 *)dst0;
  905.     const uint8 *src = (const uint8 *)src0;
  906.  
  907.     dstpitch -= 4*w;
  908.     srcpitch -= w;
  909.  
  910.     do {
  911.         vdpixsize w2 = w;
  912.  
  913.         do {
  914.             *dst++ = 0x010101 * colorconv.cliptab[colorconv.y_tab[*src++] + 277];
  915.         } while(--w2);
  916.  
  917.         vdptrstep(src, srcpitch);
  918.         vdptrstep(dst, dstpitch);
  919.     } while(--h);
  920. }
  921.  
  922. #define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h)
  923.  
  924.  
  925. namespace {
  926.     typedef void (*tpYUVPlanarFinalDecoder)(void *, const uint8 *, const uint8 *, const uint8 *, uint32);
  927.     typedef void (*tpYUVPlanarHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w);
  928.     typedef void (*tpYUVPlanarVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase);
  929. }
  930.  
  931. #ifdef _M_IX86
  932.     extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count);
  933.     extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count);
  934.     extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count);
  935. #endif
  936.  
  937.  
  938. void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) {
  939.     const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format);
  940.     int hbits = srcinfo.auxwbits;
  941.     int vbits = srcinfo.auxhbits;
  942.  
  943.     if (src.format == nsVDPixmap::kPixFormat_YUV422_UYVY || src.format == nsVDPixmap::kPixFormat_YUV422_YUYV)
  944.         hbits = 1;
  945.  
  946.     bool h_coaligned = true;
  947.     bool v_coaligned = true;
  948.  
  949.     tpYUVPlanarVertDecoder vfunc = NULL;
  950.     tpYUVPlanarHorizDecoder hfunc = NULL;
  951.     uint32 horiz_buffer_size = 0;
  952.     uint32 vert_buffer_size = 0;
  953.     uint32 horiz_count = 0;
  954.     sint32 yaccum = 8;
  955.     sint32 yinc = 8;
  956.     uint32 yleft = h;
  957.  
  958.     switch(vbits*2+v_coaligned) {
  959.     case 0:        // 4:4:4, 4:2:2
  960.     case 1:
  961.         break;
  962.     case 3:        // 4:2:0 (centered) 
  963.         vfunc = vert_expand2x_centered;
  964.         vert_buffer_size = w>>1;
  965.         yaccum = 6;
  966.         yinc = 4;
  967.         yleft >>= 1;
  968.         break;
  969.     case 5:        // 4:1:0 (centered)
  970.         vfunc = vert_expand4x_centered;
  971.         vert_buffer_size = w>>2;
  972.         yaccum = 5;
  973.         yinc = 2;
  974.         yleft >>= 2;
  975.         break;
  976.     default:
  977.         VDNEVERHERE;
  978.         return;
  979.     }
  980.  
  981.     --yleft;
  982.  
  983.     tpYUVPlanarFinalDecoder dfunc = NULL;
  984.  
  985. #ifdef _M_IX86
  986.     uint32 cpuflags = CPUGetEnabledExtensions();
  987.  
  988.     if (cpuflags & CPUF_SUPPORTS_MMX) {
  989.         switch(dst.format) {
  990.         case nsVDPixmap::kPixFormat_XRGB1555:    dfunc = vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX;    break;
  991.         case nsVDPixmap::kPixFormat_RGB565:        dfunc = vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX;    break;
  992.         case nsVDPixmap::kPixFormat_XRGB8888:    dfunc = vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX;    break;
  993.         }
  994.     }
  995. #endif
  996.  
  997.     bool halfchroma = false;
  998.  
  999.     if (!dfunc) {
  1000.         switch(dst.format) {
  1001.         case nsVDPixmap::kPixFormat_XRGB1555:        dfunc = VDYCbCrToXRGB1555Span;    break;
  1002.         case nsVDPixmap::kPixFormat_RGB565:            dfunc = VDYCbCrToRGB565Span;    break;
  1003.         case nsVDPixmap::kPixFormat_RGB888:            dfunc = VDYCbCrToRGB888Span;    break;
  1004.         case nsVDPixmap::kPixFormat_XRGB8888:        dfunc = VDYCbCrToXRGB8888Span;    break;
  1005.         case nsVDPixmap::kPixFormat_YUV422_UYVY:    dfunc = VDYCbCrToUYVYSpan;        halfchroma = true;    break;
  1006.         case nsVDPixmap::kPixFormat_YUV422_YUYV:    dfunc = VDYCbCrToYUYVSpan;        halfchroma = true;    break;
  1007.         default:
  1008.             VDNEVERHERE;
  1009.             return;
  1010.         }
  1011.     }
  1012.  
  1013.     switch(hbits*2+h_coaligned) {
  1014.     case 0:        // 4:4:4
  1015.     case 1:
  1016.         if (halfchroma) {
  1017.             hfunc = horiz_compress2x_coaligned;
  1018.             horiz_buffer_size = (w + 1) >> 1;
  1019.             horiz_count = w;
  1020.         }
  1021.         break;
  1022.     case 2:        // 4:2:0 MPEG-1 (centered)
  1023.         if (!halfchroma) {
  1024.             hfunc = horiz_expand2x_centered;
  1025.             horiz_buffer_size = w;
  1026.             horiz_count = w;
  1027.         }
  1028.         break;
  1029.     case 3:        // 4:2:0/4:2:2 MPEG-2 (coaligned)
  1030.         if (!halfchroma) {
  1031.             hfunc = horiz_expand2x_coaligned;
  1032.             horiz_buffer_size = w;
  1033.             horiz_count = w;
  1034.         }
  1035.         break;
  1036.     case 5:        // 4:1:1 (coaligned)
  1037.         if (halfchroma) {
  1038.             hfunc = horiz_expand2x_coaligned;
  1039.             horiz_buffer_size = (w + 1) >> 1;
  1040.             horiz_count = (w + 1) >> 1;
  1041.         } else {
  1042.             hfunc = horiz_expand4x_coaligned;
  1043.             horiz_buffer_size = w;
  1044.             horiz_count = w;
  1045.         }
  1046.         break;
  1047.  
  1048.     default:
  1049.         VDNEVERHERE;
  1050.         return;
  1051.     }
  1052.  
  1053.     uint32 chroma_srcwidth = -(-w >> srcinfo.auxwbits);
  1054.     horiz_buffer_size = (horiz_buffer_size + 15) & ~15;
  1055.     vert_buffer_size = (vert_buffer_size + 15) & ~15;
  1056.  
  1057.     // allocate buffers
  1058.  
  1059.     vdblock<uint8> tempbuf((horiz_buffer_size + vert_buffer_size)*2 + 1);
  1060.  
  1061.     uint8 *const crbufh = tempbuf.data();
  1062.     uint8 *const crbufv = crbufh + horiz_buffer_size;
  1063.     uint8 *const cbbufh = crbufv + vert_buffer_size;
  1064.     uint8 *const cbbufv = cbbufh + horiz_buffer_size;
  1065.  
  1066.     const uint8 *cb0 = (const uint8*)src.data2;
  1067.     const uint8 *cr0 = (const uint8*)src.data3;
  1068.     const uint8 *cb1  = cb0;
  1069.     const uint8 *cr1  = cr0;
  1070.     const uint8 *y = (const uint8 *)src.data;
  1071.     const ptrdiff_t ypitch = src.pitch;
  1072.     const ptrdiff_t cbpitch = src.pitch2;
  1073.     const ptrdiff_t crpitch = src.pitch3;
  1074.  
  1075.     void *out = dst.data;
  1076.     ptrdiff_t outpitch = dst.pitch;
  1077.  
  1078.     for(;;) {
  1079.         if (yaccum >= 8) {
  1080.             yaccum &= 7;
  1081.  
  1082.             cb0 = cb1;
  1083.             cr0 = cr1;
  1084.  
  1085.             if (yleft > 0) {
  1086.                 --yleft;
  1087.                 vdptrstep(cb1, cbpitch);
  1088.                 vdptrstep(cr1, crpitch);
  1089.             }
  1090.         }
  1091.  
  1092.         const uint8 *cr = cr0;
  1093.         const uint8 *cb = cb0;
  1094.  
  1095.         // vertical interpolation: cr
  1096.         if(yaccum & 7) {
  1097.             const uint8 *const srcs[2]={cr0, cr1};
  1098.             vfunc(crbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5);
  1099.             cr = crbufv;
  1100.         }
  1101.  
  1102.         // horizontal interpolation: cr
  1103.         if (hfunc) {
  1104.             hfunc(crbufh, cr, horiz_count);
  1105.             cr = crbufh;
  1106.         }
  1107.  
  1108.         // vertical interpolation: cb
  1109.         if(yaccum & 7) {
  1110.             const uint8 *const srcs[2]={cb0, cb1};
  1111.             vfunc(cbbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5);
  1112.             cb = cbbufv;
  1113.         }
  1114.  
  1115.         // horizontal interpolation: cb
  1116.         if (hfunc) {
  1117.             hfunc(cbbufh, cb, horiz_count);
  1118.             cb = cbbufh;
  1119.         }
  1120.  
  1121.         dfunc(out, y, cb, cr, w);
  1122.         vdptrstep(out, outpitch);
  1123.         vdptrstep(y, ypitch);
  1124.  
  1125.         if (!--h)
  1126.             break;
  1127.  
  1128.         yaccum += yinc;
  1129.     }
  1130.  
  1131. #ifdef _M_IX86
  1132.     if (cpuflags & CPUF_SUPPORTS_MMX) {
  1133.         __asm emms
  1134.     }
  1135. #endif
  1136. }
  1137.  
  1138. namespace {
  1139.     typedef void (*tpUVBltHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w);
  1140.     typedef void (*tpUVBltVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase);
  1141.  
  1142.     void uvplaneblt(uint8 *dst, ptrdiff_t dstpitch, int dstformat, const uint8 *src, ptrdiff_t srcpitch, int srcformat, vdpixsize w, vdpixsize h) {
  1143.         const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(srcformat);
  1144.         const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dstformat);
  1145.  
  1146.         int xshift = srcinfo.auxwbits - dstinfo.auxwbits;
  1147.         int yshift = srcinfo.auxhbits - dstinfo.auxhbits;
  1148.  
  1149.         tpUVBltHorizDecoder        hfunc = NULL;
  1150.         tpUVBltVertDecoder        vfunc = NULL;
  1151.  
  1152.         switch(xshift) {
  1153.         case +2:
  1154.             hfunc = horiz_expand4x_coaligned;
  1155.             break;
  1156.         case +1:
  1157.             hfunc = horiz_expand2x_coaligned;
  1158.             break;
  1159.         case  0:
  1160.             break;
  1161.         case -1:
  1162.             hfunc = horiz_compress2x_coaligned;
  1163.             break;
  1164.         case -2:
  1165.             hfunc = horiz_compress4x_coaligned;
  1166.             break;
  1167.         default:
  1168.             VDNEVERHERE;
  1169.             return;
  1170.         }
  1171.  
  1172.         int winsize, winposnext, winstep;
  1173.  
  1174.         switch(yshift) {
  1175.         case +2:
  1176.             vfunc = vert_expand4x_centered;
  1177.             winsize = 2;
  1178.             winposnext = 0xa0;
  1179.             winstep = 0x40;
  1180.             break;
  1181.         case +1:
  1182.             vfunc = vert_expand2x_centered;
  1183.             winsize = 2;
  1184.             winposnext = 0xc0;
  1185.             winstep = 0x80;
  1186.             break;
  1187.         case  0:
  1188.             winsize = 1;
  1189.             winposnext = 0;
  1190.             winstep = 0x100;
  1191.             break;
  1192.         case -1:
  1193.             vfunc = vert_compress2x_centered;
  1194.             winsize = 4;
  1195.             winposnext = 0x200;
  1196.             winstep = 0x200;
  1197.             break;
  1198.         case -2:
  1199.             vfunc = vert_compress4x_centered;
  1200.             winsize = 8;
  1201.             winposnext = 0x500;
  1202.             winstep = 0x400;
  1203.             break;
  1204.         default:
  1205.             VDNEVERHERE;
  1206.             return;
  1207.         }
  1208.  
  1209.         int dsth = -(-h >> dstinfo.auxhbits);
  1210.         int srch = -(-h >> srcinfo.auxhbits);
  1211.         int dstw = -(-w >> dstinfo.auxwbits);
  1212.         int w2 = -(-w >> std::min<int>(dstinfo.auxwbits, srcinfo.auxwbits));
  1213.  
  1214.         int winpos = (winposnext>>8) - winsize;
  1215.  
  1216.         const uint8 *window[16];
  1217.  
  1218.         vdblock<uint8> tmpbuf;
  1219.         ptrdiff_t tmppitch = (w+15) & ~15;
  1220.  
  1221.         if (vfunc && hfunc)
  1222.             tmpbuf.resize(tmppitch * winsize);
  1223.  
  1224.         do {
  1225.             int desiredpos = winposnext >> 8;
  1226.  
  1227.             while(winpos < desiredpos) {
  1228.                 const uint8 *srcrow = vdptroffset(src, srcpitch * std::max<int>(0, std::min<int>(srch-1, ++winpos)));
  1229.                 int winoffset = (winpos-1) & (winsize-1);
  1230.  
  1231.                 if (hfunc) {
  1232.                     uint8 *dstrow = vfunc ? tmpbuf.data() + tmppitch * winoffset : dst;
  1233.                     hfunc(dstrow, srcrow, w2);
  1234.                     srcrow = dstrow;
  1235.                 }
  1236.  
  1237.                 window[winoffset] = window[winoffset + winsize] = srcrow;
  1238.             }
  1239.  
  1240.             if (vfunc)
  1241.                 vfunc(dst, window + (winpos & (winsize-1)), dstw, winposnext & 255);
  1242.  
  1243.             winposnext += winstep;
  1244.             vdptrstep(dst, dstpitch);
  1245.         } while(--dsth);
  1246.      }
  1247. }
  1248.  
  1249. void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dstpm, const VDPixmap& srcpm, vdpixsize w, vdpixsize h) {
  1250.     VDMemcpyRect(dstpm.data, dstpm.pitch, srcpm.data, srcpm.pitch, dstpm.w, dstpm.h);
  1251.  
  1252.     if (srcpm.format != nsVDPixmap::kPixFormat_Y8) {
  1253.         if (dstpm.format != nsVDPixmap::kPixFormat_Y8) {
  1254.             // YCbCr -> YCbCr
  1255.             uvplaneblt((uint8 *)dstpm.data2, dstpm.pitch2, dstpm.format, (uint8 *)srcpm.data2, srcpm.pitch2, srcpm.format, w, h);
  1256.             uvplaneblt((uint8 *)dstpm.data3, dstpm.pitch3, dstpm.format, (uint8 *)srcpm.data3, srcpm.pitch3, srcpm.format, w, h);
  1257.         }
  1258.     } else {
  1259.         if (dstpm.format != nsVDPixmap::kPixFormat_Y8) {
  1260.             const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstpm.format);
  1261.             VDMemset8Rect(dstpm.data2, dstpm.pitch2, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits));
  1262.             VDMemset8Rect(dstpm.data3, dstpm.pitch3, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits));
  1263.         }
  1264.     }
  1265. }
  1266.  
  1267. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1268. extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1269. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1270. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1271. extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1272. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1273.  
  1274. DECLARE_YUV_PLANAR(YUV411, XRGB1555) {
  1275.     uint16            *out    = (uint16 *)dst.data;
  1276.     const ptrdiff_t    opitch    = dst.pitch;
  1277.     const uint8        *yrow    = (const uint8 *)src.data;
  1278.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1279.     const uint8        *crrow    = (const uint8 *)src.data3;
  1280.     const ptrdiff_t    ypitch    = src.pitch;
  1281.     const ptrdiff_t    cbpitch    = src.pitch2;
  1282.     const ptrdiff_t    crpitch    = src.pitch3;
  1283.  
  1284.     vdpixsize wpairs = (w-1)>>2;
  1285.     vdpixsize wleft = w - (wpairs<<2);
  1286.  
  1287.     do {
  1288.         uint16 *p = out;
  1289.         const uint8 *y = yrow;
  1290.         const uint8 *cb = cbrow;
  1291.         const uint8 *cr = crrow;
  1292.         vdpixsize wt;
  1293.  
  1294.         if (wpairs > 0) {
  1295. #ifdef _M_AMD64
  1296.             wt = wpairs;
  1297.  
  1298.             do {
  1299.                 const unsigned cb0 = cb[0];
  1300.                 const unsigned cb1 = cb[1];
  1301.                 const unsigned cr0 = cr[0];
  1302.                 const unsigned cr1 = cr[1];
  1303.  
  1304.                 p[0] = ycbcr_to_1555(y[0], cb0, cr0);
  1305.                 p[1] = ycbcr_to_1555(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1306.                 p[2] = ycbcr_to_1555(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1307.                 p[3] = ycbcr_to_1555(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1308.  
  1309.                 y += 4;
  1310.                 p += 4;
  1311.                 ++cb;
  1312.                 ++cr;
  1313.             } while(--wt);
  1314. #else
  1315.             vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(p, y, cb, cr, wpairs);
  1316.             y += 4*wpairs;
  1317.             cr += wpairs;
  1318.             cb += wpairs;
  1319.             p += 4*wpairs;
  1320. #endif
  1321.         }
  1322.  
  1323.         if (wleft > 0) {
  1324.             wt = wleft;
  1325.  
  1326.             const uint8 cr0 = *cr;
  1327.             const uint8 cb0 = *cb;
  1328.  
  1329.             do {
  1330.                 *p++ = ycbcr_to_1555(*y++, cb0, cr0);
  1331.             } while(--wt);
  1332.         }
  1333.  
  1334.         vdptrstep(out, opitch);
  1335.         vdptrstep(yrow, ypitch);
  1336.         vdptrstep(cbrow, cbpitch);
  1337.         vdptrstep(crrow, crpitch);
  1338.     } while(--h);
  1339.  
  1340. #ifndef _M_AMD64
  1341.     __asm emms
  1342. #endif
  1343. }
  1344.  
  1345. DECLARE_YUV_PLANAR(YUV411, RGB565) {
  1346.     uint16            *out    = (uint16 *)dst.data;
  1347.     const ptrdiff_t    opitch    = dst.pitch;
  1348.     const uint8        *yrow    = (const uint8 *)src.data;
  1349.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1350.     const uint8        *crrow    = (const uint8 *)src.data3;
  1351.     const ptrdiff_t    ypitch    = src.pitch;
  1352.     const ptrdiff_t    cbpitch    = src.pitch2;
  1353.     const ptrdiff_t    crpitch    = src.pitch3;
  1354.  
  1355.     vdpixsize wpairs = (w-1)>>2;
  1356.     vdpixsize wleft = w - (wpairs<<2);
  1357.  
  1358.     do {
  1359.         uint16 *p = out;
  1360.         const uint8 *y = yrow;
  1361.         const uint8 *cb = cbrow;
  1362.         const uint8 *cr = crrow;
  1363.         vdpixsize wt;
  1364.  
  1365.         if (wpairs > 0) {
  1366. #if _M_AMD64
  1367.             wt = wpairs;
  1368.  
  1369.             do {
  1370.                 const unsigned cb0 = cb[0];
  1371.                 const unsigned cb1 = cb[1];
  1372.                 const unsigned cr0 = cr[0];
  1373.                 const unsigned cr1 = cr[1];
  1374.  
  1375.                 p[0] = ycbcr_to_565(y[0], cb0, cr0);
  1376.                 p[1] = ycbcr_to_565(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1377.                 p[2] = ycbcr_to_565(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1378.                 p[3] = ycbcr_to_565(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1379.  
  1380.                 y += 4;
  1381.                 p += 4;
  1382.                 ++cb;
  1383.                 ++cr;
  1384.             } while(--wt);
  1385. #else
  1386.             vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(p, y, cb, cr, wpairs);
  1387. #endif
  1388.         }
  1389.  
  1390.         if (wleft > 0) {
  1391.             wt = wleft;
  1392.  
  1393.             const uint8 cr0 = *cr;
  1394.             const uint8 cb0 = *cb;
  1395.  
  1396.             do {
  1397.                 *p++ = ycbcr_to_565(*y++, cb0, cr0);
  1398.             } while(--wt);
  1399.         }
  1400.  
  1401.         vdptrstep(out, opitch);
  1402.         vdptrstep(yrow, ypitch);
  1403.         vdptrstep(cbrow, cbpitch);
  1404.         vdptrstep(crrow, crpitch);
  1405.     } while(--h);
  1406.  
  1407. #ifndef _M_AMD64
  1408.     __asm emms
  1409. #endif
  1410. }
  1411.  
  1412. DECLARE_YUV_PLANAR(YUV411, RGB888) {
  1413.     uint8            *out    = (uint8 *)dst.data;
  1414.     const ptrdiff_t    opitch    = dst.pitch;
  1415.     const uint8        *yrow    = (const uint8 *)src.data;
  1416.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1417.     const uint8        *crrow    = (const uint8 *)src.data3;
  1418.     const ptrdiff_t    ypitch    = src.pitch;
  1419.     const ptrdiff_t    cbpitch    = src.pitch2;
  1420.     const ptrdiff_t    crpitch    = src.pitch3;
  1421.  
  1422.     vdpixsize wpairs = (w-1)>>2;
  1423.     vdpixsize wleft = w - (wpairs<<2);
  1424.  
  1425.     do {
  1426.         uint8 *p = out;
  1427.         const uint8 *y = yrow;
  1428.         const uint8 *cb = cbrow;
  1429.         const uint8 *cr = crrow;
  1430.         vdpixsize wt;
  1431.  
  1432.         if (wpairs > 0) {
  1433.             wt = wpairs;
  1434.  
  1435.             do {
  1436.                 const unsigned cb0 = cb[0];
  1437.                 const unsigned cb1 = cb[1];
  1438.                 const unsigned cr0 = cr[0];
  1439.                 const unsigned cr1 = cr[1];
  1440.  
  1441.                 ycbcr_to_888(p+0, y[0], cb0, cr0);
  1442.                 ycbcr_to_888(p+3, y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1443.                 ycbcr_to_888(p+6, y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1444.                 ycbcr_to_888(p+9, y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1445.  
  1446.                 y += 4;
  1447.                 p += 12;
  1448.                 ++cb;
  1449.                 ++cr;
  1450.             } while(--wt);
  1451.         }
  1452.  
  1453.         if (wleft > 0) {
  1454.             wt = wleft;
  1455.  
  1456.             const uint8 cr0 = *cr;
  1457.             const uint8 cb0 = *cb;
  1458.  
  1459.             do {
  1460.                 ycbcr_to_888(p, *y++, cb0, cr0);
  1461.                 p += 4;
  1462.             } while(--wt);
  1463.         }
  1464.  
  1465.         vdptrstep(out, opitch);
  1466.         vdptrstep(yrow, ypitch);
  1467.         vdptrstep(cbrow, cbpitch);
  1468.         vdptrstep(crrow, crpitch);
  1469.     } while(--h);
  1470. }
  1471.  
  1472. DECLARE_YUV_PLANAR(YUV411, XRGB8888) {
  1473.     uint32            *out    = (uint32 *)dst.data;
  1474.     const ptrdiff_t    opitch    = dst.pitch;
  1475.     const uint8        *yrow    = (const uint8 *)src.data;
  1476.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1477.     const uint8        *crrow    = (const uint8 *)src.data3;
  1478.     const ptrdiff_t    ypitch    = src.pitch;
  1479.     const ptrdiff_t    cbpitch    = src.pitch2;
  1480.     const ptrdiff_t    crpitch    = src.pitch3;
  1481.  
  1482.     vdpixsize wpairs = (w-1)>>2;
  1483.     vdpixsize wleft = w - (wpairs<<2);
  1484.  
  1485.     do {
  1486.         uint32 *p = out;
  1487.         const uint8 *y = yrow;
  1488.         const uint8 *cb = cbrow;
  1489.         const uint8 *cr = crrow;
  1490.         vdpixsize wt;
  1491.  
  1492.         if (wpairs > 0) {
  1493. #ifdef _M_AMD64
  1494.             wt = wpairs;
  1495.  
  1496.             do {
  1497.                 const unsigned cb0 = cb[0];
  1498.                 const unsigned cb1 = cb[1];
  1499.                 const unsigned cr0 = cr[0];
  1500.                 const unsigned cr1 = cr[1];
  1501.  
  1502.                 p[0] = ycbcr_to_8888(y[0], cb0, cr0);
  1503.                 p[1] = ycbcr_to_8888(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1504.                 p[2] = ycbcr_to_8888(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1505.                 p[3] = ycbcr_to_8888(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1506.  
  1507.                 y += 4;
  1508.                 p += 4;
  1509.                 ++cb;
  1510.                 ++cr;
  1511.             } while(--wt);
  1512. #else
  1513.             vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(p, y, cb, cr, wpairs);
  1514.             y += 4*wpairs;
  1515.             cr += wpairs;
  1516.             cb += wpairs;
  1517.             p += 4*wpairs;
  1518. #endif
  1519.         }
  1520.  
  1521.         if (wleft > 0) {
  1522.             wt = wleft;
  1523.  
  1524.             const uint8 cr0 = *cr;
  1525.             const uint8 cb0 = *cb;
  1526.  
  1527.             do {
  1528.                 *p++ = ycbcr_to_8888(*y++, cb0, cr0);
  1529.             } while(--wt);
  1530.         }
  1531.  
  1532.         vdptrstep(out, opitch);
  1533.         vdptrstep(yrow, ypitch);
  1534.         vdptrstep(cbrow, cbpitch);
  1535.         vdptrstep(crrow, crpitch);
  1536.     } while(--h);
  1537.  
  1538. #ifndef _M_AMD64
  1539.     __asm emms
  1540. #endif
  1541. }
  1542.